<script lang="jsx">
import {
  defineComponent,
  ref,
  reactive,
  onMounted,
  onUnmounted,
  watch,
  computed,
  nextTick,
  getCurrentInstance
} from 'vue'
import { DynamicScroller, DynamicScrollerItem } from 'vue-virtual-scroller'
import 'vue-virtual-scroller/dist/vue-virtual-scroller.css'
import { ContextMenu } from './context-menu'
import { sortTreeList, getParentNode } from './tool'
import { debounce } from 'lodash-es'

export default defineComponent({
  name: 'VirtualTable',
  props: {
    data: {
      type: Array,
      required: true,
      default: () => []
    },
    rowConfig: {
      type: Object,
      default: () => ({
        keyField: 'node_id'
      })
    },
    // 配置editConfig后才可双击编辑
    editConfig: {
      type: Object,
      default: null
    },
    // 配置treeConfig后才可会做树排序
    treeConfig: {
      type: Object,
      default: null
    },
    menuConfig: {
      type: Object,
      default: () => ({
        body: {}
      })
    },
    showHeader: {
      type: Boolean,
      default: true
    },
    rowClassName: {
      type: Function,
      default: null
    },
    // A4页面配置
    pageConfig: {
      type: Object,
      default: () => ({
        enabled: false, // 是否启用A4页面模式
        pageHeight: 842, // A4页面高度 (297mm * 3.78px/mm)
        pageWidth: 595, // A4页面宽度 (210mm * 3.78px/mm)
        margin: 40, // 页面边距
        gap: 10, // 页面间隔
        showPageHeader: true // 是否显示页眉
      })
    },
    // 页面数据映射 - key是页码，value是node_id数组
    pageData: {
      type: Object,
      default: null
    }
  },
  emits: [
    'current-change',
    'menu-click',
    'edit-activated',
    'edit-closed',
    'scroll-end',
    'selection-change'
  ],
  setup(props, { emit, slots, expose }) {
    // 获取当前实例
    const $table = getCurrentInstance()
    // 组件引用
    const scrollerRef = ref()
    const isReady = ref(false)
    const currentEditRow = ref(null)
    const currentRow = ref(null)
    const tableData = ref([])
    let dataMap = new Map() // 使用Map存储节点映射
    const dataIdMap = new Map() // 仅存储ID映射，减少内存占用

    // A4页面相关状态
    const currentPage = ref(0)
    const pages = ref([])
    const pageRefs = ref([])

    // 虚拟页面加载相关
    const visiblePages = ref(new Set())
    const loadedPages = ref(new Set())
    const pageObserver = ref(null)
    const pageBuffer = 2 // 预加载前后2页

    // 行高缓存系统
    const heightCache = new WeakMap()
    const heightObserver = ref(null)

    // 数据变更标记，用于增量更新
    const lastDataHash = ref('')
    const changedItems = new Set()

    // 性能监控
    const performanceMetrics = reactive({
      renderTime: 0,
      scrollCount: 0,
      memoryUsage: 0,
      visibleItems: 0,
      cacheHitRate: 0,
      lastUpdate: Date.now()
    })

    // 性能监控工具
    const measurePerformance = (name, fn) => {
      if (!import.meta.env.DEV) {
        return fn()
      }

      const start = performance.now()
      const result = fn()
      const end = performance.now()

      if (name === 'render') {
        performanceMetrics.renderTime = end - start
      }

      return result
    }

    // 内存监控
    const updateMemoryUsage = () => {
      if (!import.meta.env.DEV || !('memory' in performance)) {
        return
      }

      performanceMetrics.memoryUsage = (performance.memory.usedJSHeapSize / 1024 / 1024).toFixed(2)
    }

    // 缓存命中率监控
    let cacheHits = 0
    let cacheRequests = 0

    const trackCacheAccess = (isHit) => {
      if (!import.meta.env.DEV) return

      cacheRequests++
      if (isHit) cacheHits++
      performanceMetrics.cacheHitRate = ((cacheHits / cacheRequests) * 100).toFixed(1)
    }

    // 安全的数据计算属性
    const safeTableData = computed(() => {
      try {
        return Array.isArray(tableData.value) ? tableData.value : []
      } catch (error) {
        // 数据处理错误，使用空数组
        return []
      }
    })

    // 动态行高计算
    const getItemSize = (item) => {
      if (!item) return 30

      // 检查缓存
      const cacheKey = `${item.content_type}_${item.content?.length || 0}_${
        item.title?.length || 0
      }_${item._editing ? 1 : 0}`
      if (heightCache.has(item)) {
        const cached = heightCache.get(item)
        if (cached.key === cacheKey) {
          trackCacheAccess(true) // 缓存命中
          return cached.height
        }
      }

      trackCacheAccess(false) // 缓存未命中

      let height = 30

      // 根据内容类型计算最小高度
      switch (item.content_type) {
        case 'image':
          height = 150 // 图片类型预设高度
          break
        case 'table':
          // 表格高度根据表格复杂度计算
          const tableContent = item.content || ''
          const tableRows = (tableContent.match(/<tr/g) || []).length
          height = Math.max(100, tableRows * 35 + 30)
          break
        case 'flowchart':
          height = 200 // 流程图类型预设高度
          break
        default:
          // 文本类型：根据内容长度和编辑状态估算高度
          const contentLength = (item.content || '').length
          const titleLength = (item.title || '').length
          const totalLength = contentLength + titleLength

          // 考虑中文字符占用更多宽度
          const chineseChars = (item.content || '').match(/[\u4e00-\u9fa5]/g)?.length || 0
          const adjustedLength = totalLength + chineseChars * 0.5

          const estimatedLines = Math.ceil(adjustedLength / 50) || 1
          height = Math.max(30, estimatedLines * 24)

          // 编辑状态下增加高度
          if (item._editing) {
            height += 20
          }
          break
      }

      // 缓存计算结果
      heightCache.set(item, { key: cacheKey, height })
      return height
    }

    // 计算动态最小行高
    const dynamicMinItemSize = computed(() => {
      if (safeTableData.value.length === 0) return 30

      // 计算前100项的平均高度作为最小行高
      const sampleData = safeTableData.value.slice(0, Math.min(100, safeTableData.value.length))
      if (sampleData.length === 0) return 30

      const avgHeight =
        sampleData.reduce((sum, item) => sum + getItemSize(item), 0) / sampleData.length
      const minSize = Math.max(24, Math.floor(avgHeight * 0.6)) // 降低到60%避免过高

      // 确保最小高度不超过60，避免滚动问题
      return Math.min(minSize, 60)
    })

    // 右键菜单处理
    let contextMenuIns

    const menuClick = (menu, row) => {
      emit('menu-click', { menu, row })
      contextMenuIns?.onClose()
      contextMenuIns = null
    }

    const onContextMenu = (e) => {
      if (!props.menuConfig?.body?.options?.length) return

      contextMenuIns?.onClose()
      contextMenuIns = null

      let targetDom = e.target
      while (
        targetDom &&
        targetDom?.getAttribute &&
        !targetDom?.getAttribute('data-id') &&
        targetDom !== scrollerRef.value?.$el
      ) {
        targetDom = targetDom.parentNode
      }
      if (targetDom?.getAttribute?.('data-id')) {
        const dataId = targetDom.getAttribute('data-id')
        const currentNode = getRowById(dataId)
        if (currentNode) {
          contextMenuIns = ContextMenu({
            e,
            row: currentNode,
            menuConfig: props.menuConfig,
            onMenuClick: menuClick
          })
          // 只有在真正显示菜单时才阻止默认行为
          e.preventDefault()
          e.stopPropagation()
        }
      }
    }

    // 编辑状态处理
    const clearEditEvent = (e) => {
      if (!currentEditRow.value) {
        return
      }
      let targetDom = e.target
      while (
        targetDom &&
        targetDom?.getAttribute &&
        !targetDom?.getAttribute('data-id') &&
        targetDom !== scrollerRef.value?.$el
      ) {
        targetDom = targetDom.parentNode
        // 富文本编辑器的弹框，不触发edit-closed事件
        if (
          targetDom?.classList &&
          ['el-popper', 'ck-body-wrapper'].some((cls) => targetDom.classList.contains(cls))
        ) {
          return
        }
      }
      if (targetDom?.getAttribute?.('data-id') != currentEditRow.value?.node_id) {
        currentEditRow.value._editing = false
        emit('edit-closed', {
          row: currentEditRow.value,
          column: {},
          $table: $table?.exposed
        })
        currentEditRow.value = null
      }
    }

    if (props.editConfig?.trigger === 'dblclick') {
      watch(
        () => currentEditRow.value,
        (val) => {
          document.removeEventListener('click', clearEditEvent, true)
          if (val) {
            setTimeout(() => {
              document.addEventListener('click', clearEditEvent, true)
            }, 200)
          }
        }
      )
    }

    // 计算数据哈希值，用于检测变更
    const getDataHash = (data) => {
      return JSON.stringify(
        data.map((item) => ({
          id: item[props.rowConfig.keyField],
          content: item.content?.length || 0,
          type: item.content_type,
          editing: item._editing
        }))
      )
    }

    // 计算页面分布
    const calculatePages = () => {
      if (!props.pageConfig.enabled) {
        pages.value = [{ items: tableData.value, startIndex: 0, endIndex: tableData.value.length }]
        return
      }

      // 如果提供了pageData，根据pageData进行分页
      if (props.pageData && Object.keys(props.pageData).length) {
        const pagesData = []
        const keyField = props.rowConfig.keyField || 'node_id'

        // 创建node_id到数据项的映射
        const itemMap = new Map()
        tableData.value.forEach((item) => {
          itemMap.set(String(item[keyField]), item)
        })

        // 按页码排序
        const pageNumbers = Object.keys(props.pageData).sort((a, b) => parseInt(a) - parseInt(b))

        pageNumbers.forEach((pageNum) => {
          const nodeIds = props.pageData[pageNum]
          const pageItems = []

          // 根据node_id数组获取对应的数据项
          nodeIds.forEach((nodeId) => {
            const item = itemMap.get(String(nodeId))
            if (item) {
              pageItems.push(item)
            }
          })

          if (pageItems.length > 0) {
            pagesData.push({
              items: pageItems,
              pageNumber: parseInt(pageNum),
              height: pageItems.reduce((sum, item) => sum + getItemSize(item), 0)
            })
          }
        })

        pages.value = pagesData
      } else {
        // 自动计算分页
        const { pageHeight, margin } = props.pageConfig
        const contentHeight = pageHeight - margin * 2
        const pagesData = []
        let currentPageItems = []
        let currentPageHeight = 0
        let startIndex = 0
        let pageNumber = 1

        tableData.value.forEach((item, index) => {
          const itemHeight = getItemSize(item)
          const itemLayer = item.layer || 0

          // 如果是高层级节点（layer <= 2），且当前页不为空，立即创建新页
          if (itemLayer <= 2 && currentPageItems.length > 0) {
            // 保存当前页
            pagesData.push({
              items: [...currentPageItems],
              startIndex,
              endIndex: index,
              height: currentPageHeight,
              pageNumber: pageNumber++
            })
            // 开始新页
            currentPageItems = [item]
            currentPageHeight = itemHeight
            startIndex = index
          } else if (
            currentPageHeight + itemHeight > contentHeight &&
            currentPageItems.length > 0
          ) {
            // 当前页已满，创建新页
            pagesData.push({
              items: [...currentPageItems],
              startIndex,
              endIndex: index,
              height: currentPageHeight,
              pageNumber: pageNumber++
            })
            currentPageItems = [item]
            currentPageHeight = itemHeight
            startIndex = index
          } else {
            currentPageItems.push(item)
            currentPageHeight += itemHeight
          }
        })

        // 添加最后一页
        if (currentPageItems.length > 0) {
          pagesData.push({
            items: currentPageItems,
            startIndex,
            endIndex: tableData.value.length,
            height: currentPageHeight,
            pageNumber: pageNumber
          })
        }

        pages.value = pagesData
      }
    }

    // 增量数据处理 - 仅处理变更的数据
    const processData = () => {
      try {
        // 确保数据是数组
        const sourceData = Array.isArray(props.data) ? props.data : []

        // 计算数据哈希，检测是否有变更
        const currentHash = getDataHash(sourceData)
        const isDataChanged = currentHash !== lastDataHash.value

        if (!isDataChanged && tableData.value.length > 0) {
          // 数据无变更，跳过处理
          return
        }

        lastDataHash.value = currentHash

        const processedData = (
          props.treeConfig ? sortTreeList(sourceData, undefined, props.treeConfig) : sourceData
        ).map((item, index) => {
          const keyValue = item[props.rowConfig.keyField]
          const existingItem = dataIdMap.get(keyValue)

          // 如果是新数据或有变更，创建新对象
          if (
            !existingItem ||
            existingItem.content !== item.content ||
            existingItem.content_type !== item.content_type
          ) {
            changedItems.add(keyValue)
            const newItem = {
              ...item,
              index,
              _editing: item._editing || false,
              _original: existingItem?._original || { ...item } // 保留原始数据，避免重复深拷贝
            }

            // 更新映射
            dataIdMap.set(keyValue, newItem)
            return newItem
          }

          // 复用现有数据，仅更新索引
          existingItem.index = index
          return existingItem
        })

        tableData.value = processedData

        // 计算页面分布
        calculatePages()

        // 清理不再存在的数据
        const currentIds = new Set(processedData.map((item) => item[props.rowConfig.keyField]))
        for (const [id] of dataIdMap) {
          if (!currentIds.has(id)) {
            dataIdMap.delete(id)
            changedItems.delete(id)
          }
        }
      } catch (error) {
        // 数据处理失败
        // 如果处理失败，使用空数组
        tableData.value = []
        pages.value = []
        dataIdMap.clear()
        changedItems.clear()
      }
    }

    // 监听数据变化，添加错误处理
    watch(
      () => props.data,
      (newData, oldData) => {
        try {
          // 检查数据有效性
          if (!Array.isArray(newData)) {
            // 数据类型无效，期望数组类型
            return
          }

          // 延迟处理数据，避免频繁更新
          nextTick(() => {
            processData()

            // 如果启用了A4页面模式，重新初始化懒加载
            if (props.pageConfig.enabled) {
              // 重置加载状态
              loadedPages.value.clear()
              visiblePages.value.clear()
              // 初始加载前3页
              for (let i = 0; i < Math.min(3, pages.value.length); i++) {
                loadedPages.value.add(i)
              }
              // 重新设置观察器
              nextTick(() => {
                setupPageObserver()
              })
            }
          })
        } catch (error) {
          // 数据监听错误
        }
      },
      { deep: false, immediate: false }
    )

    // 监听pageData变化
    watch(
      () => props.pageData,
      () => {
        if (props.pageConfig.enabled) {
          calculatePages()
          // 重置加载状态
          loadedPages.value.clear()
          visiblePages.value.clear()
          // 初始加载前3页
          for (let i = 0; i < Math.min(3, pages.value.length); i++) {
            loadedPages.value.add(i)
          }
          // 重新设置观察器
          nextTick(() => {
            setupPageObserver()
          })
        }
      },
      { deep: true }
    )

    // 监听分页模式切换
    watch(
      () => props.pageConfig.enabled,
      (enabled) => {
        if (enabled) {
          // 切换到分页模式
          nextTick(() => {
            processData()
            calculatePages()
            // 重置加载状态
            loadedPages.value.clear()
            visiblePages.value.clear()
            // 初始加载前3页
            for (let i = 0; i < Math.min(3, pages.value.length); i++) {
              loadedPages.value.add(i)
            }
            // 设置页面观察器
            nextTick(() => {
              setupPageObserver()
            })
          })
        } else {
          // 切换到虚拟滚动模式
          // 清理页面观察器
          if (pageObserver.value) {
            pageObserver.value.disconnect()
            pageObserver.value = null
          }
          // 清理页面状态
          loadedPages.value.clear()
          visiblePages.value.clear()
        }
      }
    )

    watch(currentRow, () => emit('current-change', { row: currentRow.value }))

    // ResizeObserver优化 - 替换原有的setupHeightObserver
    let resizeObserver = null
    const setupResizeObserver = () => {
      if (!window.ResizeObserver) return

      resizeObserver = new ResizeObserver((entries) => {
        for (const entry of entries) {
          const rowId = entry.target.dataset?.id
          if (!rowId) continue

          const item = getRowById(rowId)
          if (!item) continue

          const newHeight = entry.contentRect.height
          const cachedHeight = heightCache.get(item)?.height || 0

          if (Math.abs(cachedHeight - newHeight) > 5) {
            const cached = heightCache.get(item) || {}
            heightCache.set(item, { ...cached, height: newHeight })

            // 使用RAF优化更新
            requestAnimationFrame(() => {
              const itemComponent = entry.target.__vueParentComponent
              if (itemComponent?.proxy?.updateSize) {
                itemComponent.proxy.updateSize()
              }
            })
          }
        }
      })

      // 观察所有行元素
      nextTick(() => {
        const scrollerEl = scrollerRef.value?.$el
        if (!scrollerEl) return

        const items = scrollerEl.querySelectorAll('[data-id]')
        items.forEach((el) => {
          if (el.dataset.id) {
            resizeObserver.observe(el)
          }
        })
      })
    }

    // 保持原有函数名以兼容
    const setupHeightObserver = setupResizeObserver

    // 清理观察器
    const cleanupHeightObserver = () => {
      if (heightObserver.value) {
        heightObserver.value.disconnect()
        heightObserver.value = null
      }
      if (resizeObserver) {
        resizeObserver.disconnect()
        resizeObserver = null
      }
    }

    // 设置页面观察器
    const setupPageObserver = () => {
      if (!props.pageConfig.enabled) return

      // 清理旧的观察器
      if (pageObserver.value) {
        pageObserver.value.disconnect()
      }

      pageObserver.value = new IntersectionObserver(
        (entries) => {
          entries.forEach((entry) => {
            const pageIndex = parseInt(entry.target.dataset.pageIndex)
            if (entry.isIntersecting) {
              // 页面进入视口
              visiblePages.value.add(pageIndex)
              // 预加载前后页面
              for (
                let i = Math.max(0, pageIndex - pageBuffer);
                i <= Math.min(pages.value.length - 1, pageIndex + pageBuffer);
                i++
              ) {
                loadedPages.value.add(i)
              }
            } else {
              // 页面离开视口
              visiblePages.value.delete(pageIndex)
              // 清理远离视口的页面（保留缓冲区）
              setTimeout(() => {
                if (!visiblePages.value.has(pageIndex)) {
                  const shouldKeep = Array.from(visiblePages.value).some(
                    (visIdx) => Math.abs(visIdx - pageIndex) <= pageBuffer * 2
                  )
                  if (!shouldKeep) {
                    loadedPages.value.delete(pageIndex)
                  }
                }
              }, 3000) // 3秒后清理
            }
          })
        },
        {
          root: null,
          rootMargin: '100px',
          threshold: 0.01
        }
      )

      // 开始观察所有页面占位符
      nextTick(() => {
        const container = document.querySelector('.a4-pages-container')
        if (container) {
          const pagePlaceholders = container.querySelectorAll('.a4-page-placeholder')
          pagePlaceholders.forEach((placeholder) => {
            pageObserver.value.observe(placeholder)
          })
        }
      })
    }

    // 初始化
    onMounted(() => {
      processData()
      nextTick(() => {
        setupHeightObserver()
        eventDelegation.setup()

        // 注册选择相关事件
        if (props.editConfig?.trigger === 'contenteditable') {
          document.addEventListener('selectionchange', handleSelectionChange)
          document.addEventListener('mouseup', handleMouseUp)
        }

        // 初始化分页模式
        if (props.pageConfig.enabled) {
          calculatePages()
          // 初始加载前3页
          for (let i = 0; i < Math.min(3, pages.value.length); i++) {
            loadedPages.value.add(i)
          }
          // 设置页面观察器
          nextTick(() => {
            setupPageObserver()
          })
        }
      })
      isReady.value = true
    })

    // 清理
    onUnmounted(() => {
      cleanupHeightObserver()
      eventDelegation.cleanup()

      // 清理页面观察器
      if (pageObserver.value) {
        pageObserver.value.disconnect()
        pageObserver.value = null
      }

      // 清理事件监听器
      if (props.editConfig?.trigger === 'contenteditable') {
        document.removeEventListener('selectionchange', handleSelectionChange)
        document.removeEventListener('mouseup', handleMouseUp)
      }

      // 清理定时器
      if (selectionChangeTimer) {
        clearTimeout(selectionChangeTimer)
      }

      // 清理缓存
      dataMap = new Map()
      dataIdMap.clear()
      loadedPages.value.clear()
      visiblePages.value.clear()
      // heightCache 是 WeakMap，无需手动清理，会自动垃圾回收
    })

    // 事件委托优化
    const eventDelegation = {
      handlers: new Map(),

      setup() {
        nextTick(() => {
          // scrollerRef.value?.$el 就是容器.virtual-table-wrapper本身
          const container = scrollerRef.value?.$el //?.querySelector('.virtual-table-wrapper')
          if (!container) return

          // 点击事件委托
          container.addEventListener('click', this.handleClick.bind(this), { passive: true })
          container.addEventListener('dblclick', this.handleDblClick.bind(this), { passive: true })
        })
      },

      handleClick(e) {
        const row = e.target.closest('[data-id]')
        if (!row) return

        const rowId = row.dataset.id
        const item = getRowById(rowId)
        if (!item) return

        setCurrentRow(item)
      },

      handleDblClick(e) {
        if (!props.editConfig?.trigger === 'dblclick') return

        const row = e.target.closest('[data-id]')
        if (!row) return

        const rowId = row.dataset.id
        const item = getRowById(rowId)
        if (!item) return

        setEditRow(item)
      },

      cleanup() {
        const container = scrollerRef.value?.$el?.querySelector('.virtual-table-wrapper')
        if (!container) return

        container.removeEventListener('click', this.handleClick)
        container.removeEventListener('dblclick', this.handleDblClick)
      }
    }

    // 保留原始处理函数用于兼容
    const handleRowClick = (item) => {
      setCurrentRow(item)
    }
    const handleRowDblClick = (item) => setEditRow(item)

    let lastFocusedElement = null
    let debounceTimer
    const onEditFocusin = ({ row, column }, e, targetOverride) => {
      const target = targetOverride || e.target
      const mainNode = getParentNode(target, 'virtual-table-cell', scrollerRef.value?.$el)
      if (lastFocusedElement === mainNode && debounceTimer) {
        clearTimeout(debounceTimer)
        lastFocusedElement = null
      }
      // 重复选中一行，不触发
      if (currentEditRow.value?.[props.rowConfig.keyField] == row?.[props.rowConfig.keyField]) {
        return
      }
      setTimeout(() => {
        currentEditRow.value = row
        // 获取字段标识，兼容从外层contenteditable触发的场景
        let field = target?.getAttribute?.('field')
        if (!field) {
          // 优先从当前选择中定位到具有 field 属性的元素
          try {
            const sel = document.getSelection()
            let node = sel?.anchorNode
            if (node && node.nodeType === 3) node = node.parentElement
            const fieldEl = node?.closest?.('[field]')
            if (fieldEl) field = fieldEl.getAttribute('field')
          } catch (_) {}
          // 退化：从事件路径中搜索
          if (!field && e?.composedPath) {
            for (const n of e.composedPath()) {
              if (n?.getAttribute && n.getAttribute('field')) {
                field = n.getAttribute('field')
                break
              }
            }
          }
        }
        emit('edit-activated', {
          row: row,
          column: { ...column, field },
          $table: $table?.exposed
        })
        // console.log("onEditFocusin==>", row, e.target.innerText)
      }, 200)
    }
    const onEditFocusout = ({ row, column }, e, targetOverride) => {
      const target = targetOverride || e.target
      lastFocusedElement = getParentNode(target, 'virtual-table-cell', scrollerRef.value?.$el)
      if (debounceTimer) {
        clearTimeout(debounceTimer)
      }
      // contenteditable的元素内部有多个子节点时(比如table)，只触发一次
      debounceTimer = setTimeout(() => {
        const contentType = row.content_type

        // 获取字段标识，兼容从外层contenteditable触发的场景
        let field = target?.getAttribute?.('field')
        if (!field) {
          try {
            const sel = document.getSelection()
            let node = sel?.anchorNode
            if (node && node.nodeType === 3) node = node.parentElement
            const fieldEl = node?.closest?.('[field]')
            if (fieldEl) field = fieldEl.getAttribute('field')
          } catch (_) {}
          if (!field && e?.composedPath) {
            for (const n of e.composedPath()) {
              if (n?.getAttribute && n.getAttribute('field')) {
                field = n.getAttribute('field')
                break
              }
            }
          }
        }

        // // 检查是否包含diff标记，如果有则跳过更新
        // const hasDiffMarks =
        //   target?.querySelector?.('.diff-text') ||
        //   target?.closest?.('[field]')?.querySelector?.('.diff-text')

        // if (hasDiffMarks) {
        //   // 如果内容包含diff标记，不更新内容，只触发edit-closed事件
        //   emit('edit-closed', {
        //     row: row,
        //     column: { ...column, field },
        //     $table: $table?.exposed
        //   })
        //   return
        // }

        // 如果是表格，获取整个html
        if (contentType === 'table') {
          // 已经通过组件v-model更新了数据
        } else if (contentType === 'text') {
          // 只有文本类型才需要更新内容
          // 首先尝试找到具有field属性的元素
          let fieldEl = null
          let newContent = null

          // 优先使用传入的 targetOverride，避免从当前选区获取（可能已经指向新节点）
          if (target?.getAttribute?.('field')) {
            fieldEl = target
          } else if (target?.closest?.('[field]')) {
            // 从 target 向上查找，而不是从选区查找
            fieldEl = target.closest('[field]')
          }

          // 只从具有field属性的元素获取内容
          if (fieldEl) {
            newContent = fieldEl.textContent
          }

          // 只在内容真正发生变化时才更新
          // 重要：只有当 newContent 不是 undefined 且与原值不同时才更新
          if (field && newContent !== undefined && newContent !== null) {
            // 清理内容，移除多余的空白字符
            newContent = newContent.trim()
            const originalValue = row[field]?.trim() || ''
            // 只有当内容确实不同时才更新
            if (newContent !== originalValue) {
              console.log('更新字段内容:', {
                field,
                oldValue: originalValue,
                newValue: newContent
              })
              row[field] = newContent
            }
          } else if (newContent === undefined || newContent === null) {
            // 如果获取不到内容，不要更新字段，保持原值
            console.warn('警告：无法获取字段内容，保持原值', {
              field,
              fieldEl: !!fieldEl,
              currentValue: row[field]?.substring(0, 50) + '...'
            })
          }
        }

        // 对于所有类型都触发 edit-closed 事件
        emit('edit-closed', {
          row: row,
          column: { ...column, field },
          $table: $table?.exposed
        })
        // console.log("onEditFocusout==>", row, e.target.innerText)
      }, 50)
    }

    // 跟踪当前焦点所在的单元格
    let currentFocusedCell = null
    let selectionChangeTimer = null

    // 支持跨节点选择：将整个可视区域作为单一 editing host
    const handleWrapperFocusin = (e) => {
      if (props.editConfig?.trigger !== 'contenteditable') return
      handleCellFocusChange('focusin', e)
    }

    const handleWrapperFocusout = (e) => {
      if (props.editConfig?.trigger !== 'contenteditable') return
      // 当从一个单元格切换到另一个单元格时，使用上一次聚焦的单元格
      // 来确定要保存的内容，避免误用当前选区（已指向新行/新单元格）。
      if (currentFocusedCell?.cellEl) {
        // 优先使用上一次聚焦时记录的 fieldEl；若不存在，再在该 cell 内查找
        let prevFieldEl = currentFocusedCell.fieldEl
        if (!prevFieldEl && currentFocusedCell.field) {
          prevFieldEl = currentFocusedCell.cellEl?.querySelector?.(
            `[field="${currentFocusedCell.field}"]`
          )
        }
        if (!prevFieldEl) {
          prevFieldEl =
            currentFocusedCell.cellEl.querySelector?.('[field]') || currentFocusedCell.cellEl
        }
        onEditFocusout(currentFocusedCell, { target: prevFieldEl }, prevFieldEl)
        currentFocusedCell = null
      } else {
        // 回退：保持原有行为
        handleCellFocusChange('focusout', e)
      }
    }

    // 统一的焦点变化处理
    const handleCellFocusChange = (type, e) => {
      try {
        const sel = document.getSelection()
        let node = sel?.anchorNode
        if (node && node.nodeType === 3) node = node.parentElement
        const cellEl = node?.closest?.('.virtual-table-cell')
        const rowEl = node?.closest?.('.virtual-table-row')
        if (!cellEl || !rowEl) return

        const rowId = rowEl.getAttribute('data-id')
        const prop = cellEl.getAttribute('data-prop')
        const row = getRowById(rowId)
        const column = normalizedColumns.value.find((c) => `${c.prop}` === `${prop}`) || {}
        const fieldEl = node?.closest?.('[field]') || null
        const fieldAttr = fieldEl?.getAttribute?.('field') || undefined

        if (type === 'focusin') {
          currentFocusedCell = { row, column, cellEl, rowEl, fieldEl, field: fieldAttr }
          onEditFocusin({ row, column }, e, fieldEl || node?.closest?.('[field]'))
        } else {
          onEditFocusout({ row, column }, e, fieldEl || node?.closest?.('[field]'))
        }
      } catch (_) {}
    }

    // 监听选择变化，更精确地跟踪焦点
    const handleSelectionChange = () => {
      if (props.editConfig?.trigger !== 'contenteditable') return

      // 清除之前的定时器
      if (selectionChangeTimer) {
        clearTimeout(selectionChangeTimer)
      }

      // 使用定时器避免频繁触发
      selectionChangeTimer = setTimeout(() => {
        try {
          const sel = document.getSelection()
          if (sel.rangeCount === 0) return

          const range = sel.getRangeAt(0)
          let node = range.startContainer
          if (node.nodeType === 3) node = node.parentElement

          const cellEl = node?.closest?.('.virtual-table-cell')
          const rowEl = node?.closest?.('.virtual-table-row')

          if (!cellEl || !rowEl) return

          const rowId = rowEl.getAttribute('data-id')
          const prop = cellEl.getAttribute('data-prop')
          const row = getRowById(rowId)
          const column = normalizedColumns.value.find((c) => `${c.prop}` === `${prop}`) || {}

          // 检查是否切换了单元格
          if (
            !currentFocusedCell ||
            currentFocusedCell.row?.[props.rowConfig.keyField] !==
              row?.[props.rowConfig.keyField] ||
            currentFocusedCell.column?.prop !== column?.prop
          ) {
            // 触发旧单元格的 focusout
            if (currentFocusedCell) {
              // 使用之前聚焦时记录的 fieldEl；若缺失则尽力匹配字段名
              let prevFieldEl = currentFocusedCell.fieldEl
              if (!prevFieldEl && currentFocusedCell.field) {
                prevFieldEl = currentFocusedCell.cellEl?.querySelector?.(
                  `[field="${currentFocusedCell.field}"]`
                )
              }
              if (!prevFieldEl) {
                prevFieldEl =
                  currentFocusedCell.cellEl?.querySelector?.('[field]') || currentFocusedCell.cellEl
              }
              onEditFocusout(currentFocusedCell, { target: prevFieldEl }, prevFieldEl)
            }

            // 更新当前焦点单元格
            currentFocusedCell = {
              row,
              column,
              cellEl,
              rowEl,
              fieldEl: node?.closest?.('[field]') || null,
              field: (node?.closest?.('[field]') || null)?.getAttribute?.('field') || undefined
            }

            // 触发新单元格的 focusin
            onEditFocusin({ row, column }, { target: cellEl }, cellEl)
          }

          // 获取选中的文本（支持跨行）
          const selectedText = sel.toString()
          if (selectedText) {
            // 检查是否跨越多个单元格
            const endNode =
              range.endContainer.nodeType === 3
                ? range.endContainer.parentElement
                : range.endContainer
            const endCellEl = endNode?.closest?.('.virtual-table-cell')
            const endRowEl = endNode?.closest?.('.virtual-table-row')

            if (endCellEl && endRowEl && (endCellEl !== cellEl || endRowEl !== rowEl)) {
              console.log('跨单元格选择文本:', selectedText)
              console.log('从单元格:', prop, '行:', rowId)
              console.log(
                '到单元格:',
                endCellEl.getAttribute('data-prop'),
                '行:',
                endRowEl.getAttribute('data-id')
              )
            }
          }
        } catch (err) {
          console.error('Selection change error:', err)
        }
      }, 50) // 减少 debounce 延迟，提高响应速度
    }

    // 处理鼠标抬起事件，获取跨行选择的内容（并补充起止位置信息）
    const handleMouseUp = () => {
      if (props.editConfig?.trigger !== 'contenteditable') return

      setTimeout(() => {
        const sel = document.getSelection()
        if (!sel) return
        const selectedText = sel.toString()

        if (selectedText) {
          const range = sel.rangeCount > 0 ? sel.getRangeAt(0) : null
          let startMeta = null
          let endMeta = null

          try {
            if (range) {
              // 起点
              let sNode = range.startContainer
              if (sNode?.nodeType === 3) sNode = sNode.parentElement
              const sCell = sNode?.closest?.('.virtual-table-cell')
              const sRow = sNode?.closest?.('.virtual-table-row')
              startMeta =
                sCell && sRow
                  ? {
                      rowId: sRow.getAttribute('data-id'),
                      prop: sCell.getAttribute('data-prop')
                    }
                  : null

              // 终点
              let eNode = range.endContainer
              if (eNode?.nodeType === 3) eNode = eNode.parentElement
              const eCell = eNode?.closest?.('.virtual-table-cell')
              const eRow = eNode?.closest?.('.virtual-table-row')
              endMeta =
                eCell && eRow
                  ? {
                      rowId: eRow.getAttribute('data-id'),
                      prop: eCell.getAttribute('data-prop')
                    }
                  : null
            }
          } catch (_) {}

          // 通知父组件（保持原字段，同时补充起止元信息）
          emit('selection-change', {
            text: selectedText,
            selection: sel,
            range,
            start: startMeta,
            end: endMeta
          })
        }
      }, 10)
    }

    const isEditByRow = (row) => row?._editing === true
    const getParentRow = (row) => (row?.parent_id ? dataMap.get(row.parent_id) : null)
    // 获取当前节点的上一个同级节点（如果上一个节点是父节点，返回空）
    const getSiblingRow = (row) => {
      const findIdx = tableData.value.findIndex(
        (x) => x[props.rowConfig.keyField] == row[props.rowConfig.keyField]
      )
      if (findIdx < 1) {
        return null
      }
      return tableData.value[findIdx - 1]?.layer === row.layer ? tableData.value[findIdx - 1] : null
    }
    // 获取当前节点的下一个节点
    const getNextRow = (row) => {
      const findIdx = tableData.value.findIndex(
        (x) => x[props.rowConfig.keyField] == row[props.rowConfig.keyField]
      )
      if (findIdx >= tableData.value.length - 1) {
        return null
      }
      return tableData.value[findIdx + 1]
    }
    // 根据id查找数据 - 使用新的映射系统
    const getRowById = (id) => {
      if (!id) return null

      // 直接从映射中获取
      let res = dataIdMap.get(id)
      if (res) return res

      // 类型转换查找
      if (typeof id === 'number') {
        return dataIdMap.get(`${id}`)
      } else if (typeof id === 'string' && /^\d+$/.test(id)) {
        return dataIdMap.get(Number(id))
      }

      return null
    }
    // 优化的滚动到指定行 - 支持A4页面模式
    let scrollToRowRaf = null
    const scrollToRow = (row) => {
      if (scrollToRowRaf) {
        cancelAnimationFrame(scrollToRowRaf)
      }

      scrollToRowRaf = requestAnimationFrame(() => {
        const keyField = props.rowConfig.keyField
        const rowId = row[keyField]

        if (props.pageConfig.enabled) {
          // A4页面模式下的滚动
          // 查找包含该行的页面
          let targetPageIndex = -1
          let targetRowElement = null

          for (let i = 0; i < pages.value.length; i++) {
            const page = pages.value[i]
            const hasRow = page.items.some((item) => item[keyField] === rowId)
            if (hasRow) {
              targetPageIndex = i
              break
            }
          }

          if (targetPageIndex !== -1) {
            // 确保目标页面及周围页面已加载
            // 预加载前后各1页，确保滚动流畅
            for (
              let i = Math.max(0, targetPageIndex - 1);
              i <= Math.min(pages.value.length - 1, targetPageIndex + 1);
              i++
            ) {
              if (!loadedPages.value.has(i)) {
                loadedPages.value.add(i)
              }
            }

            // 滚动到对应的页面
            nextTick(() => {
              // 查找页面元素
              const container = document.querySelector('.a4-pages-container')
              if (!container) return

              // 等待页面渲染完成，然后滚动到具体的行
              const checkAndScroll = (retryCount = 0) => {
                const targetRowElement = container.querySelector(`[data-id="${rowId}"]`)

                if (targetRowElement) {
                  // 获取元素在其父容器中的绝对位置
                  // 需要考虑所有父元素的偏移
                  let elementOffsetTop = 0
                  let currentElement = targetRowElement

                  // 累计计算元素到容器顶部的实际距离
                  while (currentElement && currentElement !== container) {
                    elementOffsetTop += currentElement.offsetTop
                    currentElement = currentElement.offsetParent
                  }

                  const containerHeight = container.clientHeight

                  // 计算目标滚动位置，将行定位在视口上方 1/3 处
                  let targetScrollTop = elementOffsetTop - containerHeight * 0.3

                  // 确保不会滚动到负值
                  targetScrollTop = Math.max(0, targetScrollTop)

                  // 获取当前滚动位置
                  const currentScrollTop = container.scrollTop
                  const scrollDistance = Math.abs(targetScrollTop - currentScrollTop)

                  // 自定义平滑滚动动效
                  const smoothScrollTo = (targetTop) => {
                    const startTop = container.scrollTop
                    const distance = targetTop - startTop
                    const duration = Math.min(800, Math.max(300, scrollDistance * 0.5)) // 动态计算持续时间
                    const startTime = performance.now()

                    // 缓动函数 - easeInOutCubic
                    const easeInOutCubic = (t) => {
                      return t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2
                    }

                    const animateScroll = (currentTime) => {
                      const elapsed = currentTime - startTime
                      const progress = Math.min(elapsed / duration, 1)

                      // 应用缓动函数
                      const easedProgress = easeInOutCubic(progress)
                      const newScrollTop = startTop + distance * easedProgress

                      container.scrollTop = newScrollTop

                      if (progress < 1) {
                        requestAnimationFrame(animateScroll)
                      } else {
                        // 滚动完成后添加一个微小的回弹效果
                        setTimeout(() => {
                          container.scrollTop = targetTop
                        }, 50)
                      }
                    }

                    requestAnimationFrame(animateScroll)
                  }

                  // 根据滚动距离选择滚动方式
                  if (scrollDistance > 3000) {
                    // 距离特别远时，使用快速滚动
                    container.scrollTo({
                      top: targetScrollTop,
                      behavior: 'instant'
                    })
                  } else {
                    // 使用自定义平滑滚动
                    smoothScrollTo(targetScrollTop)
                  }

                  // 高亮效果
                  targetRowElement.classList.add('row--highlight')
                  setTimeout(() => {
                    targetRowElement.classList.remove('row--highlight')
                  }, 1500)
                } else if (retryCount < 10) {
                  // 如果元素还未渲染，稍后重试（最多重试10次）
                  setTimeout(() => checkAndScroll(retryCount + 1), 150)
                }
              }

              // 直接调用检查和滚动，不需要先滚动到页面
              setTimeout(checkAndScroll, 200)
            })
          }
        } else {
          // 虚拟滚动模式下的滚动
          const index = tableData.value.findIndex((item) => item[keyField] === rowId)
          if (index !== -1 && scrollerRef.value?.scrollToItem) {
            // 使用instant模式，避免动画带来的性能开销
            scrollerRef.value.scrollToItem(index)
          }
        }

        scrollToRowRaf = null
      })
    }
    // 设置当前选中行
    const setCurrentRow = (row) => {
      if (!row) return
      if (!isReady.value) {
        setTimeout(() => setCurrentRow(row), 200)
        return
      }

      currentRow.value = row
      if (currentRow.value !== currentEditRow.value && currentEditRow.value) {
        currentEditRow.value._editing = false
        setTimeout(() => {
          currentEditRow.value = null
        }, 200)
      }
    }
    // 设置当前编辑行
    const setEditRow = (row, field) => {
      return new Promise((resolve) => {
        if (
          props?.editConfig?.beforeEditMethod &&
          typeof props?.editConfig?.beforeEditMethod === 'function' &&
          !props.editConfig.beforeEditMethod({ row })
        ) {
          return
        }
        if (!row || !isReady.value) {
          setTimeout(() => setEditRow(row), 200)
          return
        }
        if (row === currentEditRow.value) return

        tableData.value.forEach((item) => {
          if (item._editing) {
            emit('edit-closed', {
              row: item,
              column: { field },
              $table: $table?.exposed
            })
          }
          item._editing = false
        })

        row._editing = true
        setTimeout(() => {
          currentEditRow.value = row
          emit('edit-activated', {
            row: row,
            column: { field },
            $table: $table?.exposed
          })
          resolve(true)
        })
      })
    }
    const setEditCell = (row) => {
      return setEditRow(row)
    }

    // 数据变更后的统一更新函数
    const refreshAfterDataChange = () => {
      // 如果启用了A4页面模式，更新页面加载状态
      if (props.pageConfig.enabled) {
        // 重新计算页面分布
        calculatePages()

        // 确保当前页面和附近页面被加载
        const visiblePagesArray = Array.from(visiblePages.value)
        if (visiblePagesArray.length > 0) {
          const currentPageIndex = Math.min(...visiblePagesArray)
          for (
            let i = Math.max(0, currentPageIndex - 1);
            i <= Math.min(pages.value.length - 1, currentPageIndex + 2);
            i++
          ) {
            loadedPages.value.add(i)
          }
        } else {
          // 如果没有可见页面，加载前3页
          for (let i = 0; i < Math.min(3, pages.value.length); i++) {
            loadedPages.value.add(i)
          }
        }

        // 重新设置页面观察器
        nextTick(() => {
          setupPageObserver()
        })
      }

      // 使用nextTick确保DOM更新
      nextTick(() => {
        // 强制虚拟滚动器重新计算（如果不是A4模式）
        if (!props.pageConfig.enabled && scrollerRef.value && scrollerRef.value.$forceUpdate) {
          scrollerRef.value.$forceUpdate()
        }
      })
    }

    // 插入行（在currentRow上边，currentRow=-1插入子节点）
    const insertAt = (record, currentRow) => {
      return new Promise((resolve) => {
        let findIdx = -1
        if (currentRow == -1) {
          const pRow = getRowById(record.parent_id)
          findIdx =
            tableData.value.findIndex(
              (x) => x[props.rowConfig.keyField] == pRow[props.rowConfig.keyField]
            ) + 1
          while (tableData.value[findIdx].parent_id == pRow[props.rowConfig.keyField]) {
            findIdx += 1
          }
        } else {
          findIdx = tableData.value.findIndex(
            (x) => x[props.rowConfig.keyField] == currentRow[props.rowConfig.keyField]
          )
        }
        dataMap.set(record.node_id, record)
        dataIdMap.set(record[props.rowConfig.keyField], record)
        // eslint-disable-next-line vue/no-mutating-props
        tableData.value.splice(findIdx, 0, record)

        // 触发数据变更后的更新逻辑
        refreshAfterDataChange()

        resolve({ row: record })
      })
    }

    // 插入行（在currentRow下边）
    const insertNextAt = (record, currentRow) => {
      return new Promise((resolve) => {
        const findIdx =
          tableData.value.findIndex(
            (x) => x[props.rowConfig.keyField] == currentRow[props.rowConfig.keyField]
          ) + 1
        dataMap.set(record.node_id, record)
        dataIdMap.set(record[props.rowConfig.keyField], record)
        // eslint-disable-next-line vue/no-mutating-props
        tableData.value.splice(findIdx, 0, record)

        // 触发数据变更后的更新逻辑
        refreshAfterDataChange()

        resolve({ row: record })
      })
    }
    // 删除行
    const remove = (currentRow) => {
      const findIdx = tableData.value.findIndex(
        (x) =>
          x[props.rowConfig.keyField] == currentRow[props.rowConfig.keyField] || x === currentRow
      )
      if (findIdx > -1) {
        // 从数据映射中移除
        const keyValue = currentRow[props.rowConfig.keyField]
        dataMap.delete(currentRow.node_id)
        dataIdMap.delete(keyValue)

        // 从表格数据中移除
        tableData.value.splice(findIdx, 1)

        // 触发数据变更后的更新逻辑
        refreshAfterDataChange()
      }
    }
    // 判断行是否编辑过
    const isUpdateByRow = (row, field) => {
      if (!row || !row[props.rowConfig.keyField]) return false
      const originData = row._original
      if (!originData) {
        return false
      }
      return field
        ? row[field] !== originData[field]
        : Object.keys(originData).some((key) => originData[key] !== row[key])
    }
    // 判断是否是新增的行
    const isInsertByRow = (row) => row && row[props.rowConfig.keyField] && !row._original
    const reloadRow = (row, data) => {
      if (row && row[props.rowConfig.keyField]) {
        if (data) Object.assign(row, data)
        row._original = {
          ...row,
          _editing: undefined,
          _X_ROW_CHILD: undefined,
          _original: undefined
        }
      }
    }
    // 恢复数据
    const revertData = (row) => {
      if (row && row[props.rowConfig.keyField]) {
        const originData = getRowById(row[props.rowConfig.keyField])
        if (originData._original) {
          Object.assign(originData, originData._original)
        } else {
          remove(originData)
        }
      }
    }

    // 模拟vxeTable的方法，避免历史代码报错
    const setAllTreeExpand = () => {}
    // 取消高亮选择
    const clearCurrentRow = () => {
      currentRow.value = {}
    }

    // 如果是treeConfig，找出row的所有子节点
    const getAllChilds = (row) => {
      let idx = tableData.value.findIndex(
        (item) => item[props.rowConfig.keyField] == row[props.rowConfig.keyField]
      )
      if (idx > -1 && props.treeConfig) {
        const keyField = props.treeConfig?.keyField || props.treeConfig?.rowField || 'node_id'
        const parentField = props.treeConfig?.parentField || 'parent_id'
        const findChilds = []
        // 所有父节点id（已按主子排序过，下一条肯定是上一条的子节点）
        const pidMap = new Map()
        pidMap.set(row[keyField], true)
        for (let i = idx + 1; i < tableData.value.length; i++) {
          const item = tableData.value[i]
          if (item && pidMap.has(item[parentField])) {
            findChilds.push(item)
            pidMap.set(item[keyField])
          } else {
            // 一旦找不到就终止循环
            break
          }
        }
        return findChilds
      }
      return []
    }

    // 暴露方法
    expose({
      isEditByRow,
      getParentRow,
      getSiblingRow,
      getNextRow,
      getRowById,
      scrollToRow,
      setCurrentRow,
      setEditRow,
      setEditCell,
      insertAt,
      insertNextAt,
      isUpdateByRow,
      isInsertByRow,
      reloadRow,
      revertData,
      remove,
      setAllTreeExpand,
      clearCurrentRow,
      getAllChilds,
      // 性能监控API
      getPerformanceMetrics: () => ({ ...performanceMetrics }),
      resetPerformanceMetrics: () => {
        Object.assign(performanceMetrics, {
          renderTime: 0,
          scrollCount: 0,
          memoryUsage: 0,
          visibleItems: 0,
          cacheHitRate: 0,
          lastUpdate: Date.now()
        })
        cacheHits = 0
        cacheRequests = 0
      }
    })
    // <VirtualTable>
    //   <VirtualTableColumn></VirtualTableColumn>
    //   <VirtualTableColumn></VirtualTableColumn>
    //   <VirtualTableColumn></VirtualTableColumn>
    // </VirtualTable>
    // 列组件
    const normalizedColumns = computed(() => {
      return slots
        .default()
        .filter((node) => node.type?.name === 'VirtualTableColumn')
        .map((node) => ({
          prop: node.props?.prop,
          title: node.props?.title,
          width: node.props?.width,
          slots: node.children
        }))
    })
    // 计算列宽 - 安全的样式对象返回
    const computeColumnWidth = (width) => {
      try {
        if (width === 0) {
          return { width: '0px' }
        }
        if (!width) {
          return { flex: '1 1 100%' }
        }
        return { flex: /^\d+$/.test(width) ? `0 0 ${width}px` : `0 0 ${width}` }
      } catch (error) {
        console.warn('[VirtualTable] computeColumnWidth error:', error)
        return { flex: '1 1 100%' }
      }
    }
    // 如果是树，并且配置了childCurrent高亮子节点，找出所有当前选中行的子节点
    const childRows = computed(() => {
      if (props.treeConfig?.childCurrent && currentRow.value) {
        return getAllChilds(currentRow.value).map((item) => item[props.rowConfig.keyField])
      }
      return []
    })
    const itemIndexs = ref({
      viewStartIndex: 0,
      viewEndIndex: 0,
      visibleStartIndex: 0,
      visibleEndIndex: 0
    })
    // 滚动性能优化
    let scrollRAF = null
    let updateRAF = null

    const onScrollEnd = (e, info) => {
      if (scrollRAF) {
        cancelAnimationFrame(scrollRAF)
      }
      scrollRAF = requestAnimationFrame(() => {
        // 更新性能监控
        if (import.meta.env.DEV) {
          performanceMetrics.scrollCount++
          performanceMetrics.visibleItems =
            itemIndexs.value.visibleEndIndex - itemIndexs.value.visibleStartIndex
          updateMemoryUsage()
        }

        emit('scroll-end', {
          ...itemIndexs.value
        })
        scrollRAF = null
      })
    }

    const onUpdate = (viewStartIndex, viewEndIndex, visibleStartIndex, visibleEndIndex) => {
      if (updateRAF) {
        cancelAnimationFrame(updateRAF)
      }
      updateRAF = requestAnimationFrame(() => {
        itemIndexs.value = {
          viewStartIndex,
          viewEndIndex,
          visibleStartIndex,
          visibleEndIndex
        }
        updateRAF = null
      })
    }
    // 渲染单个页面内容
    const renderPageContent = (page, pageIndex) => {
      const { pageHeight, margin } = props.pageConfig

      // 如果页面未加载，显示占位符
      if (!loadedPages.value.has(pageIndex)) {
        return (
          <div class="a4-page-loading">
            <div class="loading-spinner"></div>
            <div class="loading-text">加载中...</div>
          </div>
        )
      }

      return (
        <>
          {/* 页眉 - 每页都显示 */}
          {props.pageConfig.showPageHeader && slots['page-header']
            ? slots['page-header']?.({ pageNumber: page.pageNumber || pageIndex + 1, pageIndex })
            : null}

          {/* 表头 - 只在第一页显示 */}
          {pageIndex === 0 && props.showHeader ? (
            <div class="a4-table-header">
              <div class="virtual-table-header vxe-table--header vxe-table--header-wrapper">
                {normalizedColumns.value.map((column) => (
                  <div
                    class="vxe-header--column"
                    key={column.prop}
                    style={computeColumnWidth(column.width)}
                  >
                    <div class="vxe-cell">
                      {column.slots?.['header']
                        ? column.slots?.['header']?.({ column })
                        : column.title}
                    </div>
                  </div>
                ))}
              </div>
            </div>
          ) : null}

          {/* 页面内容 */}
          <div
            class="a4-page-content"
            style={{
              // 动态计算最小高度：A4高度(842px) - 页眉高度(~70px) - 边距(~30px)
              minHeight: props.pageConfig.showPageHeader ? '742px' : '812px'
            }}
          >
            {page.items.map((item) => (
              <div
                key={item[props.rowConfig.keyField]}
                data-id={item[props.rowConfig.keyField]}
                class={{
                  'virtual-table-row': true,
                  'vxe-body--row': true,
                  'row--current':
                    item[props.rowConfig.keyField] ===
                      currentRow.value?.[props.rowConfig.keyField] ||
                    (props.treeConfig?.childCurrent &&
                      childRows.value.includes(item[props.rowConfig.keyField]))
                }}
                style={{
                  width: '100%'
                }}
                onClick={() => handleRowClick(item)}
                onDblclick={() => handleRowDblClick(item)}
              >
                {normalizedColumns.value.map((column) => (
                  <div
                    key={column.prop}
                    class="virtual-table-cell vxe-cell"
                    style={computeColumnWidth(column.width)}
                    data-prop={column.prop}
                  >
                    {item._editing && props.editConfig?.trigger === 'dblclick'
                      ? column.slots?.['edit'] && column.slots?.['edit']?.({ row: item, column })
                      : column.slots?.['default'] &&
                        column.slots?.['default']?.({ row: item, column })}
                  </div>
                ))}
              </div>
            ))}
          </div>

          {/* 页脚 - 页码 */}
          {slots['page-footer'] ? (
            slots['page-footer']?.({ pageNumber: page.pageNumber || pageIndex + 1, pageIndex })
          ) : (
            <div class="a4-page-footer" contenteditable="false">
              <span class="page-number" contenteditable="false">
                {page.pageNumber || pageIndex + 1}
              </span>
            </div>
          )}
        </>
      )
    }

    // 渲染A4页面模式
    const renderA4Pages = () => {
      const { pageHeight, pageWidth, margin, gap } = props.pageConfig

      return (
        <div class="virtual-table vxe-table vxe-table--render-default border--none">
          <div
            class="a4-pages-container"
            contenteditable={props.editConfig?.trigger === 'contenteditable' ? 'true' : undefined}
            onContextmenu={onContextMenu}
            onFocusin={handleWrapperFocusin}
            onFocusout={handleWrapperFocusout}
          >
            {pages.value.map((page, pageIndex) => {
              // 始终启用懒加载
              const shouldRenderContent = loadedPages.value.has(pageIndex)

              return (
                <div
                  key={`page-${pageIndex}`}
                  class={shouldRenderContent ? 'a4-page' : 'a4-page-placeholder'}
                  data-page-index={pageIndex}
                  style={{
                    width: `${pageWidth}px`,
                    // 不设置minHeight，让内容自然决定高度
                    marginBottom: `${gap}px`,
                    padding: shouldRenderContent ? `${margin}px` : '0',
                    boxSizing: 'border-box',
                    // 使用relative定位，确保内部元素定位正确
                    position: 'relative',
                    // 确保内容能够正常撑开
                    overflow: 'visible'
                  }}
                >
                  {/* 使用伪占位元素保证最小高度 */}
                  <div
                    style={{
                      position: 'absolute',
                      top: 0,
                      left: 0,
                      width: '1px',
                      height: `${pageHeight}px`,
                      visibility: 'hidden',
                      pointerEvents: 'none'
                    }}
                  />
                  {renderPageContent(page, pageIndex)}
                </div>
              )
            })}
          </div>
        </div>
      )
    }

    // 渲染原始虚拟滚动模式
    const renderVirtualScroll = () => (
      <div class="virtual-table vxe-table vxe-table--render-default border--none">
        {props.showHeader ? (
          <div class="virtual-table-header vxe-table--header vxe-table--header-wrapper">
            {normalizedColumns.value.map((column) => (
              <div
                class="vxe-header--column"
                key={column.prop}
                style={computeColumnWidth(column.width)}
              >
                <div class="vxe-cell">
                  {column.slots?.['header'] ? column.slots?.['header']?.({ column }) : column.title}
                </div>
                <div class="vxe-resizable is--line"></div>
              </div>
            ))}
          </div>
        ) : undefined}

        <DynamicScroller
          ref={scrollerRef}
          items={safeTableData.value}
          minItemSize={dynamicMinItemSize.value}
          keyField={props.rowConfig.keyField}
          emitUpdate={false}
          buffer={300}
          class="virtual-table-wrapper"
          contenteditable={props.editConfig?.trigger === 'contenteditable' ? 'true' : undefined}
          onContextmenu={onContextMenu}
          onScrollend={onScrollEnd}
          onUpdate={onUpdate}
          onFocusin={handleWrapperFocusin}
          onFocusout={handleWrapperFocusout}
          v-slots={{
            default: ({ item, index, active }) => (
              <DynamicScrollerItem
                key={item[props.rowConfig.keyField]}
                item={item}
                active={active}
                sizeDependencies={[item.content?.length, item._editing, item.content_type]}
                data-id={item[props.rowConfig.keyField]}
                data-index={index}
                data-active={active}
                class={{
                  'virtual-table-row': true,
                  'vxe-body--row': true,
                  'row--current':
                    item[props.rowConfig.keyField] ===
                      currentRow.value?.[props.rowConfig.keyField] ||
                    // 如果是树，并且配置了childCurrent高亮子节点
                    (props.treeConfig?.childCurrent &&
                      childRows.value.includes(item[props.rowConfig.keyField]))
                }}
              >
                {normalizedColumns.value.map((column) => (
                  <div
                    key={column.prop}
                    class="virtual-table-cell vxe-cell"
                    style={computeColumnWidth(column.width)}
                    data-prop={column.prop}
                  >
                    {item._editing && props.editConfig?.trigger === 'dblclick'
                      ? column.slots?.['edit'] && column.slots?.['edit']?.({ row: item, column })
                      : column.slots?.['default'] &&
                        column.slots?.['default']?.({ row: item, column })}
                  </div>
                ))}
              </DynamicScrollerItem>
            )
          }}
        />
      </div>
    )

    // 渲染函数
    return () => {
      if (props.pageConfig.enabled) {
        return renderA4Pages()
      } else {
        return renderVirtualScroll()
      }
    }
  }
})
</script>
<style scoped>
.virtual-table {
  width: 100%;
  height: 100%;
  background-color: var(--vxe-table-body-background-color);
  display: flex;
  flex-direction: column;
}

.virtual-table .virtual-table-header {
  display: flex;
}

.virtual-table .virtual-table-wrapper {
  flex: 1;
  /* 默认字体 */
  font-family: 'FangSong';
}

.virtual-table .virtual-table-row {
  display: flex;
  min-height: 24px;
}

.virtual-table .virtual-table-row.current-row {
  background-color: var(--el-table-row-hover-bg-color);
  color: var(--el-color-primary);
}

.virtual-table .virtual-table-cell {
  position: relative;
}

.virtual-table .content-wrapper {
  flex: 1;
  min-height: 24px;
  color: rgb(96, 98, 102);
  font-size: 14px;
  font-weight: normal;
}

.virtual-table .virtual-table-inline-editing-trigger {
  white-space: pre-line;
  word-break: break-all;
  border: 1px transparent dotted;
}

.virtual-table .virtual-table-inline-editing-trigger:hover {
  border-color: var(--el-color-primary);
}

/* A4页面样式 */
.a4-pages-container {
  width: 100%;
  height: 100%;
  overflow: auto;
  background-color: #f0f0f0;
  padding: 20px;
  display: flex;
  flex-direction: column;
  align-items: center;
  /* 默认字体 */
  font-family: 'FangSong';
}

.a4-page {
  background: white;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
  position: relative;
  margin: 0 auto;
  box-sizing: border-box;
  /* 确保内容能够正常流动 */
  display: block;
  /* 最小高度通过内部占位元素实现 */
  overflow: visible;
}

.a4-table-header {
  background: white;
  z-index: 10;
  border-bottom: 1px solid #e8e8e8;
  margin-bottom: 10px;
  padding-bottom: 10px;
  overflow-x: auto;
  min-width: 0;
  margin-top: 10px;
}

/* 表头滚动条样式 */
.a4-table-header::-webkit-scrollbar {
  height: 4px;
}

.a4-table-header::-webkit-scrollbar-track {
  background: transparent;
}

.a4-table-header::-webkit-scrollbar-thumb {
  background: #ddd;
  border-radius: 2px;
}

.a4-page-content {
  /* 内容区域正常布局，不使用flex */
  min-width: 0;
  overflow: visible;
  position: relative;
}

/* 内容区域滚动条样式 */
.a4-page-content::-webkit-scrollbar {
  height: 6px;
}

.a4-page-content::-webkit-scrollbar-track {
  background: #f1f1f1;
  border-radius: 3px;
}

.a4-page-content::-webkit-scrollbar-thumb {
  background: #888;
  border-radius: 3px;
}

.a4-page-content::-webkit-scrollbar-thumb:hover {
  background: #555;
}

.a4-page-footer {
  position: absolute;
  bottom: 5px;
  left: 0;
  width: 100%;
  text-align: center;
  color: #666;
  font-size: 12px;
  background: white;
}

.page-number {
  display: inline-block;
}

/* 页面内的表格行样式 */
.a4-page .virtual-table-row {
  display: flex;
  transition: background-color 0.2s;
  width: 100%;
}

/* 表格单元格样式优化 */
.a4-page .virtual-table-cell {
  overflow: hidden;
  text-overflow: ellipsis;
  box-sizing: border-box;
}

/* 确保表头和内容对齐 */
.a4-page .virtual-table-header {
  min-width: fit-content;
}

.a4-page .vxe-header--column {
  flex-shrink: 0;
  padding: 8px;
  box-sizing: border-box;
}

.a4-page .virtual-table-row:hover {
  background-color: #fafafa;
}

.a4-page .virtual-table-row.row--current {
  background-color: var(--el-table-row-hover-bg-color);
  color: var(--el-color-primary);
}

/* 行高亮动画 - 用于scrollToRow */
.virtual-table-row.row--highlight {
  animation: rowHighlight 1.5s ease-in-out;
}

@keyframes rowHighlight {
  0% {
    background-color: transparent;
  }
  25% {
    background-color: #ffd700;
    transform: scale(1.01);
  }
  50% {
    background-color: #ffeb3b;
  }
  100% {
    background-color: transparent;
    transform: scale(1);
  }
}

/* 页面占位符样式 */
.a4-page-placeholder {
  background: white;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
  position: relative;
  margin: 0 auto;
  box-sizing: border-box;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* 加载中样式 */
.a4-page-loading {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-height: 400px;
  width: 100%;
}

.loading-spinner {
  width: 40px;
  height: 40px;
  border: 3px solid #f3f3f3;
  border-top: 3px solid var(--el-color-primary);
  border-radius: 50%;
  animation: spin 1s linear infinite;
}

@keyframes spin {
  0% {
    transform: rotate(0deg);
  }
  100% {
    transform: rotate(360deg);
  }
}

.loading-text {
  margin-top: 20px;
  color: #666;
  font-size: 14px;
}

/* 打印样式 */
@media print {
  .a4-pages-container {
    background: none;
    padding: 0;
  }

  .a4-page {
    box-shadow: none;
    margin: 0;
    page-break-after: always;
  }

  .a4-page:last-child {
    page-break-after: auto;
  }

  .a4-page-footer {
    position: fixed;
    bottom: 0;
  }
}
</style>
